﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Web;

namespace Risesun.Web
{
    internal class HttpWebPageHolder
    {
        private static readonly SortedDictionary<string, Func<HttpContext,IHttpAction>> Funcs;

        private static readonly HttpWebPageHolder Holder;

        static HttpWebPageHolder()
        {
            Funcs = new SortedDictionary<string, Func<HttpContext, IHttpAction>>();
            Holder = new HttpWebPageHolder();
        }

        private HttpWebPageHolder()
        {
            string[] files = Directory.GetFiles(HttpContext.Current.Server.MapPath("~/bin"), "*.WebApp.dll");
            foreach (string file in files)
            {
                Assembly assembly = Assembly.LoadFile(file);
                Type[] types = assembly.GetTypes();
                foreach (Type type in types)
                {
                    var attr = type.GetCustomAttribute<ControllerAttribute>();
                    if (attr == null)
                    {
                        continue;
                    }

                    MethodInfo[] members = type.GetMethods();
                    foreach (MethodInfo member in members)
                    {
                        if (member.ReturnType != typeof(IHttpAction))
                        {
                            continue;
                        }

                        var context = Expression.Parameter(typeof(HttpContext), "context");

                        var request = context.Request();

                        var init = Expression.MemberInit(
                            Expression.New(type), Expression.Bind(
                                type.GetMember("Context").First(),
                                context));

                        var list = member.GetParameters().Select(parameter => request.RequestExpress(parameter.Name, parameter.ParameterType));

                        var call = Expression.Call(init, member, list);
                        var func = Expression.Lambda<Func<HttpContext, IHttpAction>>(call, context).Compile();
                        var typeName = type.Name.Substring(0, type.Name.Length - 10);
                        var name = string.Format("/{0}/{1}.aspx", typeName, member.Name).ToLower();
                        Funcs.Add(name, func);
                    }
                }
            }
        }

        public static HttpWebPageHolder Current
        {
            get { return Holder; }
        }

        public Func<HttpContext, IHttpAction> this[HttpContext context]
        {
            get
            {
                string url = context.Request.Url.AbsolutePath.ToLower();
                if (string.IsNullOrEmpty(url) || url == "/")
                {
                    url = "/home/index.aspx";
                }

                Func<HttpContext, IHttpAction> func;
                Funcs.TryGetValue(url, out func);
                return func;
            }
        }
    }
}